/**
 * Factory creatures class
 * Uses to get data of Aliens and Humans from DB
 * Uses to place humans and aliens to map
 */
class xT_Factory_Aliens extends Actor notplaceable;
/*
//=============================================================================
// Variables
//=============================================================================
var xcT_GameInfo                                GameInfo;
var X_COM_DatabaseMgr                           mDBmgr;
var X_COM_DLLAPI                                mDLLAPI;
var Rotator                                     SpawnRotation; //Rotation of creature.
var array<int>                                  AlienAutoIncrementLevel; //TEST!!!!!
var array<X_COM_Pawn_Data>                      HumanData; //Pawn characteristics

var class<xcT_Pawn>                             DefaultPawnClass;

//=============================================================================
// Events
//=============================================================================
event PreBeginPlay()
{
	Super.PreBeginPlay();
}

event PostBeginPlay()
{
	Super.PostBeginPlay();	
	GameInfo = xcT_GameInfo(WorldInfo.Game);
}

//=============================================================================
// Functions: Spawn correction
//=============================================================================
/** Trace Actor under location */
function Actor ActorUnderTraceLocation(vector aTraceLocation)
{
	local Vector lTraceLocation,lHitLocation, lHitNormal;
	local Vector lTraceStart, lTraceEnd;	
	local Actor lActor;
	lActor = none;	
	lTraceLocation = aTraceLocation;
	lTraceLocation.z = -32;
	lTraceStart = lTraceLocation+vect(0,0,780);
	lTraceEnd = lTraceLocation;
	lActor=Trace(lHitLocation, lHitNormal, lTraceEnd, lTraceStart, true);
	return lActor;
}

/** If under creature is not ground then we need location correction */
function bool CheckCorrectionNeeded(Actor aActorUnder)
{
	local bool  lResult;
	lResult = true;
	if ((aActorUnder.isA('xcT_Tile_StaticMeshTile')) || (aActorUnder.isA('xcT_Tile_FracturedMeshTile'))) lResult = false; 
	return lResult;
}


function vector GetNewGridLocationX(vector aOLDLocation)
{
	local vector lNewGridLocation;
	lNewGridLocation = aOLDLocation;
	lNewGridLocation.x = aOLDLocation.x + class'X_COM_Settings'.default.T_GridSize.x/2;
	return lNewGridLocation;
}

function vector GetNewGridLocationY(vector aOLDLocation)
{
	local vector lNewGridLocation;
	lNewGridLocation = aOLDLocation;
	lNewGridLocation.y = aOLDLocation.y + class'X_COM_Settings'.default.T_GridSize.y/2;
	return lNewGridLocation;
}

function vector CorrectSpawnLocation(vector aSpawnLocation)
{
	local bool  bDoCorrection;
	local vector lCorrectedLocation;

	bDoCorrection=TRUE;
	
	lCorrectedLocation = aSpawnLocation; 
	bDoCorrection = CheckCorrectionNeeded(ActorUnderTraceLocation(lCorrectedLocation));
	while (bDoCorrection)
	{
		lCorrectedLocation = GetNewGridLocationX(lCorrectedLocation);
		bDoCorrection = CheckCorrectionNeeded(ActorUnderTraceLocation(lCorrectedLocation));
		if (bDoCorrection)
		{
			lCorrectedLocation = GetNewGridLocationY(lCorrectedLocation);
			bDoCorrection = CheckCorrectionNeeded(ActorUnderTraceLocation(lCorrectedLocation));
		}
		`log("Spawn Location Corrected from : "$aSpawnLocation$" to "$lCorrectedLocation);
	}
	return lCorrectedLocation;
}

//=============================================================================
// Functions: Add creatures to map
//=============================================================================
function AddCreatures(vector aSpawnLocation, rotator aSpawnRotation, EAlienCreatureKinds aAlienCreatureKind, int AliensQuantity)
{
	local int il, lStatusEnum;

	mDBmgr = GameInfo.getDBMgr();
	mDLLAPI = mDBmgr.getDLLAPI();

	mDLLAPI.SQL_selectDatabase(mDBmgr.mGameplayDatabaseIdx);

	if (mDLLAPI.SQL_queryDatabase("SELECT * FROM SOLDIERS;"))
	{
		while(mDLLAPI.SQL_nextResult())
		{
			mDLLAPI.SQL_getValueInt(1, lStatusEnum);
			if (lStatusEnum == ESS_Active)
			{
				GetHumanData(); // Gets human data from gameplay DB in array
			}
		}
	}

	mDLLAPI.SQL_selectDatabase(mDBmgr.mContentDatabaseIdx);

	// Get rest of human data from content DB
	for(il=0; il<HumanData.Length; ++il)
	{
		GetHumanDefence(il);
		GetHumanRanks(il);
		GetShield(il);
		AddXCOM(aSpawnLocation, aSpawnRotation, il); // Add soldier to map
	}

	HumanData.Remove(0,HumanData.Length-1); // Clear HumanData array

	/** Aliens **/
	for(il=0; il<AliensQuantity; ++il)
	{
		AddUFOs(aAlienCreatureKind); // Add aliens to map
	}
}

/** Fill Data array from gameplay DB */
function GetHumanData()
{
	local X_COM_Pawn_Data Data;
	local int lPhotoID, tmpINT;
		
	Data = new()class'X_COM_Pawn_Data';
	Data.InitStrings();

	Data.Race.CreatureType = ECT_Human;
	mDLLAPI.SQL_getValueString(3, Data.DisplayName);
	mDLLAPI.SQL_getValueInt(4, tmpINT);
	Data.Race.HumanCreatureKind = EHumanCreatureKinds((tmpINT));
	mDLLAPI.SQL_getValueInt(5, lPhotoID);
	if (Data.Race.HumanCreatureKind == EHCK_Male)
		Data.Photo = (Texture2D(DynamicLoadObject("xc_Faces.Human.Male.Textures.Face0"$lPhotoID,class'Texture2D')));
	else
		Data.Photo = (Texture2D(DynamicLoadObject("xc_Faces.Human.Female.Textures.Face0"$lPhotoID,class'Texture2D')));
	mDLLAPI.SQL_getValueInt(6, tmpINT);
	Data.Rank.HumanRankType = EHumanSoldierRanks((tmpINT));
	mDLLAPI.SQL_getValueInt(7, Data.Experience);
	mDLLAPI.SQL_getValueInt(8, Data.Level);
	mDLLAPI.SQL_getValueInt(9, tmpINT);
	Data.Armor.HumanDefenceType = EHumanArmorDefenceTypes((tmpINT));
	mDLLAPI.SQL_getValueInt(10, Data.Dexterity);
	mDLLAPI.SQL_getValueInt(11, Data.Vitality);
	mDLLAPI.SQL_getValueInt(12, Data.Bravery);
	mDLLAPI.SQL_getValueInt(13, Data.PainfulThreshold);
	mDLLAPI.SQL_getValueInt(14, Data.Strength);
	mDLLAPI.SQL_getValueInt(15, Data.Reaction);
	mDLLAPI.SQL_getValueInt(16, Data.FiringAccuracy);
	mDLLAPI.SQL_getValueInt(17, Data.ThrowingAccuracy);
	mDLLAPI.SQL_getValueInt(18, Data.PsionicPower);
	mDLLAPI.SQL_getValueInt(19, tmpINT);
	Data.Shield.ShieldType = EShieldTypes(tmpINT);

	HumanData.AddItem(Data);

	//For increment alien level. See CreateUFOsSoldier()
	AlienAutoIncrementLevel.AddItem(Data.Level);
}

/** Get Defence for soldier from content DB */
function GetHumanDefence(int index)
{
	local ArmorDefence lArmor;

	if (mDLLAPI.SQL_queryDatabase("SELECT * FROM DEFENCE_HUMAN WHERE ID="$(int(HumanData[index].Armor.HumanDefenceType))$";"))
	{
		lArmor = HumanData[index].Armor; 
		while(mDLLAPI.SQL_nextResult())
		{
			mDLLAPI.SQL_getValueString(1, lArmor.Title);
			mDLLAPI.SQL_getValueInt(2, lArmor.Penetrating);
			mDLLAPI.SQL_getValueInt(3, lArmor.Thermal);
			mDLLAPI.SQL_getValueInt(4, lArmor.Chemical);
			mDLLAPI.SQL_getValueInt(5, lArmor.Shock);
			mDLLAPI.SQL_getValueInt(6, lArmor.Special);
			mDLLAPI.SQL_getValueInt(7, lArmor.EMP);	
		}
		
		HumanData[index].Armor = lArmor;
	}
}

/** Get Rank for soldier from content DB */
function GetHumanRanks(int index)
{
	local string lTitle;
	if (mDLLAPI.SQL_queryDatabase("SELECT * FROM RANKS_HUMAN WHERE ID="$(int(HumanData[index].Rank.HumanRankType))$";"))
	{
		lTitle = class'X_COM_Defines'.static.initString(30);
		while(mDLLAPI.SQL_nextResult())
		{
			mDLLAPI.SQL_getValueString(1, lTitle);
			HumanData[index].Rank.Title = lTitle;
		}
	}
}

/** Get Shield for soldier from content DB */
function GetShield(int index)
{
	local string lTitle;
	local int lShieldDefence;
	if (mDLLAPI.SQL_queryDatabase("SELECT * FROM SHIELDS WHERE ID="$(int(HumanData[index].Shield.ShieldType))$";"))
	{
		lTitle = class'X_COM_Defines'.static.initString(30);
		while(mDLLAPI.SQL_nextResult())
		{
			mDLLAPI.SQL_getValueString(1, lTitle);
			HumanData[index].Shield.Title = lTitle;
			mDLLAPI.SQL_getValueInt(2, lShieldDefence);
			HumanData[index].Shield.Defence = lShieldDefence;
		}
	}
}

/** Add soldiers to map */
function AddXCOM(vector aSpawnLocation, rotator aSpawnRotation, int Index)
{
	local xcT_Pawn_XCOM lNewPawn;
	local vector lNewLocation;
	local rotator lNewRotation;	

	lNewLocation=aSpawnLocation;
	lNewLocation.x+=float(rand(960));
	lNewLocation.y+=float(rand(960));
	lNewLocation = CorrectSpawnLocation(class'xcT_Defines'.static.GetGridCoord(lNewLocation));
	lNewLocation.z=64;
	lNewRotation=aSpawnRotation;

		lNewPawn = Spawn(class'xcT_Pawn_XCOM',,,lNewLocation,lNewRotation,,false);
		if(lNewPawn != None)
		{
			CreateXCOMSoldier(lNewPawn, Index);
			GameInfo.SetPlayerDefaults(lNewPawn);
			lNewPawn.SetTeam(X_COM_TEAM);
			lNewPawn.SetCharacterClassFromInfo();
		}
		else `log("ERROR: Pawn Spawn Failure");
}

/** Add aliens to map */
function AddUFOs(EAlienCreatureKinds AlienCreatureKind)
{
	local xcT_Pawn_UFO lNewPawn;
	local vector lNewLocation;
	local rotator lNewRotation;

	lNewLocation = vect(0,0,0);
	lNewRotation = rot(0,0,0);

	lNewLocation.x=float(rand(class'X_COM_Settings'.default.T_LevelSize.X));
	lNewLocation.y=float(rand(class'X_COM_Settings'.default.T_LevelSize.Y));
	lNewLocation=CorrectSpawnLocation(class'xcT_Defines'.static.GetGridCoord(lNewLocation));
	lNewLocation.z=64;
	lNewRotation.YAW=Rand(65536);

		lNewPawn = Spawn(class'xcT_Pawn_UFO',,,lNewLocation,lNewRotation,,false);
		if(lNewPawn != None)
		{
			CreateUFOsSoldier(lNewPawn, AlienCreatureKind);
			GameInfo.SetPlayerDefaults(lNewPawn);
			lNewPawn.SetTeam(UFO_TEAM);
			lNewPawn.SetCharacterClassFromInfo();
		}
}

function CreateUFOsSoldier(xcT_Pawn aPawn, EAlienCreatureKinds aAlienCreatureKind)
{
	local xcT_Weapons WeaponTemplate; //????????
	local int il;
	local float AlienLevelModifier; //Level Modifier depends on x-com higher soldier level.
	local float RaceModifier; //Race Modifier depends on alien race
	local float RankModifier; //Rank Modifier
	local int NewAlienLevel;

	aPawn.Data.Race.CreatureType = ECT_Alien;

	mDLLAPI.SQL_selectDatabase(mDBmgr.mContentDatabaseIdx);

	//Mesh: Select mesh and other properties from race defaults
	switch (aAlienCreatureKind)
	{
		case EACK_Intoid	:   aPawn.Data.Race.AlienCreatureKind = EACK_Intoid;
								aPawn.Data.DisplayName = "Intoid";
								aPawn.Data.Photo = Texture2D'xc_Faces.Alien.Textures.test_alien_face1';
								aPawn.Mesh.SetSkeletalMesh(CreateCreatureMesh("CH_LIAM_Cathode.Mesh.SK_CH_LIAM_Cathode"));  //need to be got from some preset for alien race
								aPawn.Mesh.SetPhysicsAsset(CreateCreaturePhysAsset("CH_AnimCorrupt.Mesh.SK_CH_Corrupt_Male_Physics"), true); //need to be got from some preset for alien race
								aPawn.Mesh.AnimSets.AddItem(CreateCreatureAnimSet("CH_AnimHuman.Anims.K_AnimHuman_AimOffset")); //need to be got from some preset for alien race
								aPawn.Mesh.AnimSets.AddItem(CreateCreatureAnimSet("CH_AnimHuman.Anims.K_AnimHuman_BaseMale")); //need to be got from some preset for alien race
								aPawn.Mesh.SetAnimTreeTemplate(CreateCreatureAnimTree("CH_AnimHuman_Tree.AT_CH_Human")); //need to be got from some preset for alien race
								RaceModifier = 1 + (RandRange(1,2)/10);
								//race specific characteristics:
								aPawn.Data.Dexterity = 10;
								aPawn.Data.Vitality = 15;

		break;
	}
	
	//Status
	aPawn.Data.Status = ESS_Active; 

	//EAlienSoldierRanks
	//NEED to think about preority for soldiers! because soldiers should be most of alien team
	switch (Rand(6)+1)
	{
		case EASR_Soldier	    :   aPawn.Data.Rank.AlienRankType = EASR_Soldier;
									aPawn.Data.Rank.Title = "Soldier";
									RankModifier=1.05;
		break;
		case EASR_Leader	    :   aPawn.Data.Rank.AlienRankType = EASR_Leader;
									aPawn.Data.Rank.Title = "Leader";
									RankModifier=1.10;  
		break;
		case EASR_Commander	    :   aPawn.Data.Rank.AlienRankType = EASR_Commander;
									aPawn.Data.Rank.Title = "Commander";
									RankModifier=1.15;
		break;
		case EASR_Medic	        :   aPawn.Data.Rank.AlienRankType = EASR_Medic;
									aPawn.Data.Rank.Title = "Medic";
									RankModifier=0.85;
		break;
		case EASR_Navigator	    :   aPawn.Data.Rank.AlienRankType = EASR_Navigator;
									aPawn.Data.Rank.Title = "Navigator";
									RankModifier=0.95;
		break;
		case EASR_Scientist	    :   aPawn.Data.Rank.AlienRankType = EASR_Scientist;
									aPawn.Data.Rank.Title = "Scientist";
									RankModifier=0.90;
		break;
	}

	aPawn.Data.Experience = 0; //not used for aliens

	//Set up level modifier:
	AlienLevelModifier = 0;
	for(il=0;il<AlienAutoIncrementLevel.Length; ++il) //looking for the highest x-com level
	{
		if (AlienLevelModifier < AlienAutoIncrementLevel[il]) NewAlienLevel = AlienAutoIncrementLevel[il]; 
	}
	
	AlienLevelModifier = 1 + (NewAlienLevel)/50; // EXAMPLE : if x-com soldier level = 10 then alien Data multiplyed on 1.2 (20%)

	aPawn.Data.Level = NewAlienLevel + Rand(5);

	//Set up Data with modifier:
	aPawn.Data.Dexterity += int(AlienLevelModifier * RaceModifier * RankModifier * RandRange(50,60));
	aPawn.Data.Vitality += int(AlienLevelModifier * RaceModifier * RankModifier * RandRange(50,60));
	aPawn.Data.Bravery += int(AlienLevelModifier * RaceModifier * RankModifier * RandRange(50,60));
	aPawn.Data.PainfulThreshold += int(AlienLevelModifier * RaceModifier * RankModifier * RandRange(50,60));
	aPawn.Data.Strength += int(AlienLevelModifier * RaceModifier * RankModifier * RandRange(50,60));
	aPawn.Data.Reaction += int(AlienLevelModifier * RaceModifier * RankModifier * RandRange(50,60));
	aPawn.Data.FiringAccuracy += int(AlienLevelModifier * RaceModifier * RankModifier * RandRange(50,60));
	aPawn.Data.ThrowingAccuracy += int(AlienLevelModifier * RaceModifier * RankModifier * RandRange(50,60));
	aPawn.Data.PsionicPower += int(AlienLevelModifier * RaceModifier * RankModifier * RandRange(50,60));

	aPawn.Data.InitUnitsData();

	//Setup default armor settings:
	//aPawn.Data.SetupAlienDefenceDefaults();
	if (mDLLAPI.SQL_queryDatabase("SELECT * FROM DEFENCE_ALIEN WHERE ID="$(int(aPawn.Data.Race.AlienCreatureKind))$";"))
	{
		while(mDLLAPI.SQL_nextResult())
		{
			mDLLAPI.SQL_getValueString(1, aPawn.Data.Armor.Title);
			mDLLAPI.SQL_getValueInt(2, aPawn.Data.Armor.Penetrating);
			mDLLAPI.SQL_getValueInt(3, aPawn.Data.Armor.Thermal);
			mDLLAPI.SQL_getValueInt(4, aPawn.Data.Armor.Chemical);
			mDLLAPI.SQL_getValueInt(5, aPawn.Data.Armor.Shock);
			mDLLAPI.SQL_getValueInt(6, aPawn.Data.Armor.Special);
			mDLLAPI.SQL_getValueInt(7, aPawn.Data.Armor.EMP);	
		}
	}

	//Life
	aPawn.Health = aPawn.Data.HealthUnitsRemain;
	aPawn.HealthMax = aPawn.Data.HealthUnits;

	//Weapon:
	WeaponTemplate=spawn(class'xcT_Weapons_LinkGun');
	aPawn.CreateInventoryFromTemplate(WeaponTemplate); //give it weapon 
}

function CreateXCOMSoldier(xcT_Pawn aPawn, int Index)
{
	local xcT_Weapons WeaponTemplate; //????????

	aPawn.Data = HumanData[Index]; //get pawn data from array with index
	aPawn.Data.InitUnitsData();
	//`log("Level : "$aPawn.Data.Level$" ModifierPercent : "$aPawn.Data.ModifierPercent$" LevelModifier : "$aPawn.Data.LevelModifier);

	//Mesh:
	switch (aPawn.Data.Armor.HumanDefenceType)
	{
		case EXADT_Standart     :	aPawn.Mesh.SetSkeletalMesh(CreateCreatureMesh("xc_M_sol_LA.Mesh.xc_M_sol_LA"));
									//aPawn.CylinderComponent.SetCylinderSize(25,5);
									aPawn.Mesh.SetPhysicsAsset(CreateCreaturePhysAsset("CH_AnimCorrupt.Mesh.SK_CH_Corrupt_Male_Physics"), true);						
		break;
		case EXADT_Light        :	aPawn.Mesh.SetSkeletalMesh(CreateCreatureMesh("xc_M_sol_MA.Mesh.xc_M_sol_Armor1"));
									aPawn.Mesh.SetPhysicsAsset(CreateCreaturePhysAsset("CH_AnimCorrupt.Mesh.SK_CH_Corrupt_Male_Physics"), true);						
		break;
		case EXADT_Heavy        :	aPawn.Mesh.SetSkeletalMesh(CreateCreatureMesh("CH_IronGuard_Male.Mesh.SK_CH_IronGuard_MaleA"));
									aPawn.Mesh.SetPhysicsAsset(CreateCreaturePhysAsset("CH_AnimCorrupt.Mesh.SK_CH_Corrupt_Male_Physics"), true);						
		break;
		case EXADT_HeavyFly     :	aPawn.Mesh.SetSkeletalMesh(CreateCreatureMesh("CH_IronGuard_Male.Mesh.SK_CH_IronGuard_MaleA"));
									aPawn.Mesh.SetPhysicsAsset(CreateCreaturePhysAsset("CH_AnimCorrupt.Mesh.SK_CH_Corrupt_Male_Physics"), true);						
		break;
		case EXADT_ExoSkeleton	:	aPawn.Mesh.SetSkeletalMesh(CreateCreatureMesh("CH_IronGuard_Male.Mesh.SK_CH_IronGuard_MaleA"));
									aPawn.Mesh.SetPhysicsAsset(CreateCreaturePhysAsset("CH_AnimCorrupt.Mesh.SK_CH_Corrupt_Male_Physics"), true);						
		break;
		case EXADT_Space        :	aPawn.Mesh.SetSkeletalMesh(CreateCreatureMesh("CH_IronGuard_Male.Mesh.SK_CH_IronGuard_MaleA"));
									aPawn.Mesh.SetPhysicsAsset(CreateCreaturePhysAsset("CH_AnimCorrupt.Mesh.SK_CH_Corrupt_Male_Physics"), true);						
		break;
	}
	
	//Life
	aPawn.Health = aPawn.Data.HealthUnitsRemain;
	aPawn.HealthMax = aPawn.Data.HealthUnits;

	//Weapon:
	WeaponTemplate = spawn(class'xcT_Weapons_Riffle');
	//WeaponTemplate=spawn(class'xcT_Weapons_Grenade');
	aPawn.CreateInventoryFromTemplate(WeaponTemplate); //give it weapon 
}

//=============================================================================
// Functions: Dynamically load objects
//=============================================================================
function SkeletalMesh CreateCreatureMesh(string aObjectName)
{
	return SkeletalMesh(DynamicLoadObject(aObjectName,class'SkeletalMesh'));
}

function PhysicsAsset CreateCreaturePhysAsset(string aObjectName)
{
	return PhysicsAsset(DynamicLoadObject(aObjectName,class'PhysicsAsset'));
}

function AnimSet CreateCreatureAnimSet(string aObjectName)
{
	return AnimSet(DynamicLoadObject(aObjectName,class'AnimSet'));
}

function AnimTree CreateCreatureAnimTree(string aObjectName)
{
	return AnimTree(DynamicLoadObject(aObjectName,class'AnimTree'));
}

//=============================================================================
// Default Properties
//=============================================================================
DefaultProperties
{
	DefaultPawnClass = class'xcT_Pawn'
}
*/